#include "qqmusic.h"
#include "ui_qqmusic.h"
#include"commonpage.h"



#include<QMouseEvent>
#include<QGraphicsDropShadowEffect>
#include<QDebug>
#include<QJsonObject>
#include<QJsonArray>
#include<QFileDialog>
#include<QMessageBox>
#include<QSqlError>
#include<QSqlQuery>
#include<QSystemTrayIcon>
#include<QMenu>

QQMusic::QQMusic(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::QQMusic)
{
    ui->setupUi(this);
    //窗口初始化
    initui();
    // 初始化播放器
    initPlay();
    //初始化数据库
    initSQLite();

    initMusicList();

    //构造函数的时候调用一下
    connectSignalAndSlots();
}


QQMusic::~QQMusic()
{
    delete ui;
}



void QQMusic::initui()
{
    // 添加托盘
    // 创建托盘图标
    QSystemTrayIcon *trayIcon = new QSystemTrayIcon(this);
    trayIcon->setIcon(QIcon(":/images/tubiao.png"));

    // 创建托盘菜单
    QMenu *trayMenu = new QMenu(this);
    trayMenu->addAction("还原", this, &QWidget::showNormal);
    trayMenu->addSeparator();
    trayMenu->addAction("退出", this, &QQMusic::quitQQMusic);
    // 将托盘菜单添加到托盘图标
    trayIcon->setContextMenu(trayMenu);
    // 显⽰托盘
    trayIcon->show();

    //设置窗口为无标题
    this->setWindowFlag(Qt::FramelessWindowHint);

    //把窗口背景设为透明
    setAttribute(Qt::WA_TranslucentBackground);

    //把窗口最大化按钮禁用
    ui->max->setEnabled(false);

    //设置在状态栏中的图标
    this->setWindowIcon(QIcon(":/images/tubiao.png"));

    //设置窗口阴影
    QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect(this);
    shadowEffect->setOffset(0,0);
    shadowEffect->setColor("#000000");
    shadowEffect->setBlurRadius(0);
    this->setGraphicsEffect(shadowEffect);

    //给btForm设置按钮设置图片和pageId
    ui->rec->setIconAndText(":/images/rec.png","推荐",0);
    ui->radio->setIconAndText(":/images/radio.png","电台",1);
    ui->musicHall->setIconAndText(":/images/music.png","音乐馆",2);
    ui->like->setIconAndText(":/images/like.png","我喜欢",3);
    ui->local->setIconAndText(":/images/local.png","本地下载",4);
    ui->recent->setIconAndText(":/images/recent.png","最近播放",5);

    //把本地音乐设为默认界面动画效果
    ui->local->showAnimal();
    ui->stackedWidget->setCurrentIndex(4);
    ui->local-> setStyleSheet("#btStyle{background-color:rgb(30,206,154)}QLabel{font-family:微软雅黑}");
    currentPage = ui->localPage;//当前播放歌曲的页面默认


    //在构造中调用一下randomPiction
    randomPiction();

    //初始化推荐页面
    //生成随机数种子只生成一次就可以
    srand(time(NULL));
    //将randomPiction中保存的数据运用到recBox中的recBoxUi方法
    ui->recMusicBox->recBoxUi(randomPiction(),1);
    ui->supplyMiscBox->recBoxUi(randomPiction(),2);

    //初始化commonPage页面

    ui->localPage->setCommonPageUi("本地音乐",":/images/localbg.png");

    ui->recentPage->setCommonPageUi("最近播放",":/images/recentbg.png");

    ui->likePage->setCommonPageUi("我喜欢",":/images/ilikebg.png");

    //音乐控制区
    ui->play->setIcon(QIcon(":/images/play_2.png")); // 默认为暂停图标
    ui->playMode->setIcon(QIcon(":/images/shuffle_2.png")); // 默认为随机播放
    ui->playMode->setToolTip("随机播放");

    //在qqMusic中添加volumnToll类
    volumeTool = new VolumeTool(this);

    //将lrc默认设置成隐藏
    lrcPage = new LrcPage(this);
    lrcPage->hide();
    //给lrcPage添加动画效果
    lrcAnimation = new QPropertyAnimation(lrcPage,"geometry",this);
    lrcAnimation->setDuration(250);//持续时间
    lrcAnimation->setStartValue(QRect(0,lrcPage->height(),lrcPage->width(),lrcPage->height()));//起始帧
    lrcAnimation->setEndValue(QRect(0,0,lrcPage->width(),lrcPage->height()));//结束帧
    //初始化的时候不启动，当点击显示歌词按钮时再启动

}

void QQMusic::initPlay()
{
    //创建QmediaPlayer对象
    mediaPlayer = new QMediaPlayer(this);
    //创建QMediaPlaylist对象
    mediaPlaylist = new QMediaPlaylist(this);
    //设置播放模式，默认设为循环模式
    mediaPlaylist->setPlaybackMode(QMediaPlaylist::Random);
    // 将播放列表设置给播放器
    mediaPlayer->setPlaylist(mediaPlaylist);
    //默认音量设置为20
    mediaPlayer->setVolume(20);

}

void QQMusic::initSQLite()
{
    //创建数库连接
   sqlite = QSqlDatabase::addDatabase("QSQLITE");
    //设置数据库名称
    sqlite.setDatabaseName("QQMusic.db");
    //打开数据库
    if(!sqlite.open())
    {
        QMessageBox::critical(this,"打开QQMusicDB失败",sqlite.lastError().text());
        return;
    }
    qDebug()<<"SQLite连接成功，并创建 [QQMusic.db] 数据库!!!";

    //创建数据库表
    QString sql = ("CREATE TABLE IF NOT EXISTS musicInfo(\
                     id INTEGER PRIMARY KEY AUTOINCREMENT,\
                      musicId varchar(200) UNIQUE,\
                      musicName varchar(50),\
                      singerName varchar(50),\
                      albumName varchar(50),\
                      duration BIGINT,\
                      musicUrl varchar(256),\
                      isLike INTEGER,\
                      isHistory INTEGER)"
                      );
   //QSqlQuery对象
   QSqlQuery query;
    if(!query.exec(sql))
    {

        QMessageBox::critical(this,"数据表失败",query.lastError().text());
        return;
    }
    qDebug()<<"创建 [musicInfo] 表成功!!!";

}

void QQMusic::initMusicList()
{
    //从数据库中读取数据
    musicList.readFromDB();
    // 设置CommonPage的信息
     ui->likePage->setPageType(PageType::LIKE_PAGE);
     ui->likePage->refresh(musicList);

     ui->localPage->setPageType(PageType::LOCAL_PAGE);
     ui->localPage->refresh(musicList);

     ui->recentPage->setPageType(PageType::HISTORY_PAGE);
     ui->recentPage->refresh(musicList);
}

void QQMusic::quitQQMusic()
{
    // 歌曲信息写⼊数据库
     musicList.writeToDB();
     // 断开与SQLite的链接
     sqlite.close();
     // 关闭窗⼝
     close();
}

QJsonArray QQMusic::randomPiction()
{
    QVector<QString> vRecImageName;
    vRecImageName<<"001.png"<<"003.png"<<"004.png"<<"005.png"<<"006.png"<<"007.png"
                 <<"008.png"<<"009.png"<<"010.png"<<"011.png"<<"012.png"<<"013.png"
                 <<"014.png"<<"015.png"<<"016.png"<<"017.png"<<"018.png"<<"019.png"
                 <<"020.png"<<"021.png"<<"022.png"<<"023.png"<<"024.png"<<"025.png"
                 <<"026.png"<<"027.png"<<"028.png"<<"029.png"<<"030.png"<<"031.png"
                 <<"032.png"<<"033.png"<<"034.png"<<"035.png"<<"036.png"<<"037.png"
                 <<"038.png"<<"039.png";

    //打散顺序
    std::random_shuffle(vRecImageName.begin(),vRecImageName.end());

    //将图片和图片下面的文本对应起来，可以使用unorder_map,这里用QJsonObject
    QJsonArray objArry;
    for(int i = 0;i<vRecImageName.size();i++)
    {
        QJsonObject obj;
        obj.insert("path",":/images/rec/"+vRecImageName[i]);

        QString strText = QString("推荐-%1      ").arg(i+1,3,10,QChar('0'));
        obj.insert("text",strText);

        //把图片和文本弄成键值对后保存到QJsonArry数组中
        objArry.append(obj);
    }
    return objArry;
}

void QQMusic::connectSignalAndSlots()
{
    //把btForm发出来的信号与槽函数关联起来,转换页面
    connect(ui->rec,&BTForm::btClicked,this,&QQMusic::onBtFormClicked);
    connect(ui->radio,&BTForm::btClicked,this,&QQMusic::onBtFormClicked);
    connect(ui->musicHall,&BTForm::btClicked,this,&QQMusic::onBtFormClicked);
    connect(ui->like,&BTForm::btClicked,this,&QQMusic::onBtFormClicked);
    connect(ui->local,&BTForm::btClicked,this,&QQMusic::onBtFormClicked);
    connect(ui->recent,&BTForm::btClicked,this,&QQMusic::onBtFormClicked);

    //收藏和不收藏的处理
    connect(ui->localPage,&CommonPage::updateLikeMusic,this,&QQMusic::updateLikeMusicAndPage);
    connect(ui->likePage,&CommonPage::updateLikeMusic,this,&QQMusic::updateLikeMusicAndPage);
    connect(ui->recentPage,&CommonPage::updateLikeMusic,this,&QQMusic::updateLikeMusicAndPage);

    //音乐控制区
    connect(ui->playUp,&QPushButton::clicked,this,&QQMusic::onPlayUp);//上一曲
    connect(ui->playDown,&QPushButton::clicked,this,&QQMusic::onPlayDown);//下一曲
    connect(ui->playMode,&QPushButton::clicked,this,&QQMusic::onPlayModeClicked);//播放模式切换
    connect(mediaPlaylist,&QMediaPlaylist::playbackModeChanged,this,&QQMusic::onBackModeChange);//mediaPlaylist发生播放模式改变

    //3个commonpage页面的播放所有按钮
    connect(ui->localPage,&CommonPage::playAll,this,&QQMusic::onPlayAll);
    connect(ui->likePage,&CommonPage::playAll,this,&QQMusic::onPlayAll);
    connect(ui->recentPage,&CommonPage::playAll,this,&QQMusic::onPlayAll);

    //3个commonpage页面的鼠标双击播放歌曲
    connect(ui->localPage,&CommonPage::playMusicByIndex,this,&QQMusic::playMusicByIndex);
    connect(ui->likePage,&CommonPage::playMusicByIndex,this,&QQMusic::playMusicByIndex);
    connect(ui->recentPage,&CommonPage::playMusicByIndex,this,&QQMusic::playMusicByIndex);

    //当playlist中播放源发生改变时
    connect(mediaPlaylist,&QMediaPlaylist::currentIndexChanged,this,&QQMusic::onCurrentIndexChanged);

    //对于来自volumetool的静音信号和槽函数的关联
    connect(volumeTool,&VolumeTool::setSilence,this,&QQMusic::setMusicSilence);

    //对于来自volumetool的音量调整信号和槽函数的关联
    connect(volumeTool,&VolumeTool::setMusicVolume,this,&QQMusic::setPlayerVolume);

    // 歌曲持续时⻓改变时的信号关联槽
    connect(mediaPlayer,&QMediaPlayer::durationChanged,this,&QQMusic::onDurationChanged);
    // 歌曲的播放进度改变时信号关联槽
    connect(mediaPlayer,&QMediaPlayer::positionChanged,this,&QQMusic::onPositionChanged);

    // 当进度条改变时
    connect(ui->processBar,&MusicSlider::setMusicSliderPosition,this,&QQMusic::onMusicSliderChanged);

    //当歌曲元数据发生改变时的信号和槽
    connect(mediaPlayer,&QMediaPlayer::metaDataAvailableChanged,this,&QQMusic::onMetaDataAvailableChangedChanged);

    //当显示歌词按钮被点击
    connect(ui->lrcWord,&QPushButton::clicked,this,&QQMusic::onLrcWordClicked);

}


void QQMusic::mousePressEvent(QMouseEvent *event)
{
    //当鼠标按下时候获取其在全局窗口的位置
    if(event->button() == Qt::LeftButton)
    {
        this->isDrag = true;
       dragPosition = event->globalPos() - this->geometry().topLeft();
       return;
    }
    //如果不是左键就交给父类处理
    QWidget::mousePressEvent(event);

}

void QQMusic::mouseMoveEvent(QMouseEvent *event)
{
    //当鼠标左键移动时移动窗口
    if(event->buttons() == Qt::LeftButton &&isDrag)
    {
        move(event->globalPos() - dragPosition);
        return;
    }
    //如果不是左键就交给父类处理
    QWidget::mouseMoveEvent(event);
}



void QQMusic::on_quit_clicked()
{
    this->hide();
}

void QQMusic::onBtFormClicked(int pageId)
{
    //先把在初始化时的默认页面的背景和动画效果去掉
    ui->local->hideAnimal();
    ui->local->setStyleSheet("#btStyle:hover{background-color:#D8D8D8;}");

    //找出所有的BTForm类的控件
    QList<BTForm*> buFormList = this->findChildren<BTForm*>();
    for(auto list : buFormList)
    {
        //如果是点击页面需要处理的
        if(list->getPageId() == pageId)
        {
            //将点击页面的lineBox动画显示出来
            list->showAnimal();
        }

        //如果是非点击页面需要处理的
        if(list->getPageId() != pageId)
        {
            //需要清除非点击页面的背景
            list->clearbackground();
            //需要隐藏非点击页面的动画效果
            list->hideAnimal();
        }

    }

    ui->stackedWidget->setCurrentIndex(pageId);//将statacked设置成当前页码
    this->isDrag = false;


}

void QQMusic::updateLikeMusicAndPage(bool isLike, const QString &musicId)
{
    //修改状态
    auto it = musicList.findMusicById(musicId);
    if(it != musicList.end())
    {
        it->setIsLike(isLike);
    }
    //各个页面修改自己的Music
    ui->localPage->refresh(musicList);
    ui->likePage->refresh(musicList);
    ui->recentPage->refresh(musicList);
}


//volumn按钮被按下
void QQMusic::on_volume_clicked()
{
    //设置volume坐标
    //现在volume的坐标是相对于电脑窗口
    //所有需要把volumeBt也按照全局坐标来获取
    QPoint btPoint = ui->volume->mapToGlobal(QPoint(0,0));

    //移动volumeTool工作
    QPoint toolPoint = btPoint - QPoint(volumeTool->width()/2-10,volumeTool->height());
    //根据运行起来的界面进一步优化volume的位置
    toolPoint.setX(toolPoint.x()+5);
    toolPoint.setY(toolPoint.y()+20);
    volumeTool->move(toolPoint);


    //显示volume
    volumeTool->show();




}

void QQMusic::on_addLocal_clicked()
{
    //创建文本对话框
    QFileDialog fileDialog(this);
    fileDialog.setWindowTitle("添加本地音乐");

    //把对话框设置成“打开”格式
    fileDialog.setAcceptMode(QFileDialog::AcceptOpen);

    //设置对话框模式
    //只能选择文件，且一次可以选多个存在文件
    fileDialog.setFileMode(QFileDialog::ExistingFiles);

    //设置对话框的MIME过滤器
    QStringList mimeList;
    mimeList<<"application/octet-stream"; //application/octet-stream 相当于所有文件和没有设置一样
    fileDialog.setMimeTypeFilters(mimeList);

     //设置对话框默认的打开路径,设置⽬录为当前⼯程所在⽬录
     QDir dir(QDir::currentPath());
     dir.cdUp();
     QString musicPath = dir.path()+"/ImitationQQMusic/musics/";
     fileDialog.setDirectory(musicPath);
     //qDebug()<<musicPath;

     //对对话框中的按钮反馈 reject对应取消
     if(QDialog::Accepted == fileDialog.exec())
     {
         //获取已选中的文件的url
         QList<QUrl> fileUrls = fileDialog.selectedUrls();
         //将文件信息填充到本地下载中去
        musicList.addMusicByUrls(fileUrls);

        //将歌曲信息更新到CommonPage页面中的listWidget中
        //有可能当前页面在其他页面，为了看到效果所以要将CommonPage切换到本地下载的页面
        ui->stackedWidget->setCurrentIndex(4);

        ui->localPage->refresh(musicList);

        //在从之前播放列表是空的,在更新本地页面后把相关页面的播放器添加了
        ui->localPage->addMusicToPlayer(musicList,mediaPlaylist);

     }



}

void QQMusic::on_play_clicked()
{
    if(mediaPlayer->state() == QMediaPlayer::PlayingState)
    {
        //此时音乐正在播放，点击后即暂停
        mediaPlayer->stop();
        ui->play->setIcon(QIcon(":/images/play3.png"));

    }
    else if(mediaPlayer->state() == QMediaPlayer::StoppedState)
    {
        //此时音乐是停止，点击后即播放音乐
        mediaPlayer->play();
        ui->play->setIcon(QIcon(":/images/play_on.png"));
    }
    else if(mediaPlayer->state() == QMediaPlayer::PausedState)
    {
        //此时音乐是暂停播放状态，点击后即播放音乐
        mediaPlayer->play();
        ui->play->setIcon(QIcon(":/images/play_on.png"));
    }
}

void QQMusic::onPlayUp()
{
    mediaPlaylist->previous();
}

void QQMusic::onPlayDown()
{
    mediaPlaylist->next();
}

void QQMusic::onPlayModeClicked()
{
    if(mediaPlaylist->playbackMode() == QMediaPlaylist::Loop)
    {
        //当前是列表循环播放模式,点击后设置为随机播放
        mediaPlaylist->setPlaybackMode(QMediaPlaylist::Random);
        ui->playMode->setToolTip("随机播放");
    }
    else if(mediaPlaylist->playbackMode() == QMediaPlaylist::Random)
    {
        //当前是随机播放模式,点击后设置为单曲循环播放
        mediaPlaylist->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop);
        ui->playMode->setToolTip("单曲循环");
    }
    else if(mediaPlaylist->playbackMode() == QMediaPlaylist::CurrentItemInLoop)
    {
        //当前是单曲循环，点击后设置为列表循环
        mediaPlaylist->setPlaybackMode(QMediaPlaylist::Loop);
        ui->playMode->setToolTip("列表循环");
    }
}

void QQMusic::onBackModeChange(QMediaPlaylist::PlaybackMode mode)
{
    if(mode == QMediaPlaylist::Loop)
    {
        ui->playMode->setIcon(QIcon(":/images/list_play.png"));
    }
    else if(mode == QMediaPlaylist::Random)
    {
        ui->playMode->setIcon(QIcon(":/images/shuffle_2.png"));
    }
    else if(mode == QMediaPlaylist::CurrentItemInLoop)
    {
        ui->playMode->setIcon(QIcon(":/images/single_play.png"));
    }
}

void QQMusic::onPlayAll(PageType page)
{

    //播放page对应的页面所有歌曲默认从第0首开始播放
    CommonPage* commonPageType = ui->localPage;
    switch (page)
    {
    case PageType::LIKE_PAGE:
        commonPageType = ui->likePage;
        break;
    case PageType::LOCAL_PAGE:
        commonPageType = ui->localPage;
        break;
    case PageType::HISTORY_PAGE:
        commonPageType = ui->recentPage;
        break;
    default:
        qDebug()<<"不支持的页面";
    }



    //此时就找到了对应的播放页面
    playAllMusicOfCommonPage(commonPageType,0);//默认从第0首开始播放

}

void QQMusic::playAllMusicOfCommonPage(CommonPage *commonPageType, int index)
{
    //将play的图标改变
    ui->play->setIcon(QIcon(":images/play_on.png"));
    //把当前正在播放歌曲页面修改
    currentPage = commonPageType;

    //先清空QMediaPlaylist中的歌曲
    mediaPlaylist->clear();

    //添加当前要播放的page页面中的所有歌曲
    commonPageType->addMusicToPlayer(musicList,mediaPlaylist);

    //将当前要播放的索引设置为0
    mediaPlaylist->setCurrentIndex(index);

    mediaPlayer->play();

}

void QQMusic::playMusicByIndex(CommonPage *commonPageType, int index)
{
    playAllMusicOfCommonPage(commonPageType,index);
}

void QQMusic::onCurrentIndexChanged(int index)
{
    this->currentMusicIndex = index;
    //commonPage页面中的歌曲和正在播放的播放列表的先后顺序是相同的
    //知道歌曲在playlist中 的索引后，直接到commonpage中获取
    //playlist中的歌曲就是根据commonpage中的musicpageofpage加载的

    //通过索引拿到歌曲，然后把歌曲的isHistory改变

    QString musicId = currentPage->getMusicIdByIndex(index);

    auto it = musicList.findMusicById(musicId);
    if(it != musicList.end())
    {
        it->setIsHistory(true);
    }
    ui->recentPage->refresh(musicList);
}

void QQMusic::setMusicSilence(bool isMuted)
{   //用lamda表达式也可以
    mediaPlayer->setMuted(isMuted);
}

void QQMusic::setPlayerVolume(int volume)
{
    //用lamda表达式也可以
    mediaPlayer->setVolume(volume);
}

void QQMusic::onDurationChanged(qint64 duration)
{
    this->totalTime = duration;
    ui->totalTime->setText(QString("%1:%2").arg(duration/1000/60, 2, 10, QChar('0'))
                           .arg(duration/1000%60,2,10, QChar('0')));
}

void QQMusic::onPositionChanged(qint64 position)
{
    ui->currentTime->setText(QString("%1:%2").arg(position/1000/60, 2, 10, QChar('0'))
                             .arg(position/1000%60,2,10, QChar('0')));
    ui->processBar->setStep((float)position / (float)totalTime);

    // 同步lrc歌词
     if(mediaPlaylist->currentIndex() >= 0)
     {
       lrcPage->showLrcWord(position);
     }
}

void QQMusic::onMusicSliderChanged(float ratio)
{
    // 1. 计算当前seek位置的时⻓
    //即根据进度条与总宽度的比率，更新当前时间
     qint64 duration = (qint64)(totalTime * ratio);

     ui->currentTime->setText(QString("%1:%2").arg(duration/1000/60, 2, 10, QChar('0'))
                                              .arg(duration/1000%60, 2, 10, QChar('0')));

     // 3. 设置当前播放位置
     mediaPlayer->setPosition(duration);
}

void QQMusic::onMetaDataAvailableChangedChanged(bool available)
{
     //1、从player播放歌曲的元数据中获取歌曲信息
//法1：     QString singer = mediaPlayer->metaData("Author").toStringList().join(",");
//     QString musicName = mediaPlayer->metaData("Title").toString();

    //法2
    QString musicId = currentPage->getMusicIdByIndex(currentMusicIndex);
    auto it = musicList.findMusicById(musicId);
    QString musicName("未知歌曲");
    QString musicSinger("未知歌手");
    if(it != musicList.end())
    {
        musicName = it->getMusicName();
        musicSinger = it->getSingerName();
    }
    ui->musicName->setText(musicName);
    ui->musicSinger->setText(musicSinger);

    // 2. 获取封⾯图⽚
     QVariant coverImage = mediaPlayer->metaData("ThumbnailImage");
     if(coverImage.isValid())
      {
      // 获取封⾯图⽚成功
      QImage image = coverImage.value<QImage>();
      // 设置封⾯图⽚
      ui->musicCover->setPixmap(QPixmap::fromImage(image));
      // 缩放填充到整个Label
      ui->musicCover->setScaledContents(true);
      currentPage->setImageLabel(QPixmap::fromImage(image));
     }

     //设置歌词显示的头部信息
     lrcPage->setHeadInfo(musicName,musicSinger);

     // 歌曲名称、歌曲作者直接到Musci对象中获取
     // 此时需要知道媒体源在播放列表中的索引
     QString musicId2 = currentPage->getMusicIdByIndex(currentMusicIndex);
     auto it2 = musicList.findMusicById(musicId);

     // 加载lrc歌词并解析
      if(it2 != musicList.end())
      {
         lrcPage->parseLrc(it->getLrcFilePath());
      }
}

void QQMusic::onLrcWordClicked()
{
    lrcPage->show();
    lrcAnimation->start();
}



void QQMusic::on_skin_clicked()
{
    QMessageBox::information(this,"换肤信息","温馨提示：换肤功能正在赶工");
}

void QQMusic::on_min_clicked()
{
    this->showMinimized();
}

void QQMusic::on_max_clicked()
{
    this->showMaximized();
}
